package com.nine.demo.filemanager.file;

import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import com.nine.demo.filemanager.config.AliyunOssConfig;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * @Description:
 * @Author: 刘超
 * @Date: 2023-03-24 10:52
 */
public class AliyunOssClient implements FileManager{

    private static Logger logger = LoggerFactory.getLogger(AliyunOssClient.class);
    private OSS ossClient;
    private String bucketName;
    private AliyunOssConfig config;

    public AliyunOssConfig getConfig() {
        return config;
    }

    public OSS getOssClient() {
        return ossClient;
    }

    public void setOssClient(OSS ossClient) {
        this.ossClient = ossClient;
    }

    public String getBucketName() {
        return bucketName;
    }

    public void setBucketName(String bucketName) {
        this.bucketName = bucketName;
    }

    public void setConfig(AliyunOssConfig config) {
        this.config = config;
    }

    void init() {
        this.bucketName = config.getBucketName();
        if (config == null) {
            this.ossClient = new OSSClientBuilder().build(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret(), config.getConf());
        } else {
            this.ossClient = new OSSClientBuilder().build(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret());
        }
    }

    void destroy() {
        this.ossClient.shutdown();
    }

    public boolean saveFile(String bucketName, String filename, @NotNull String content) {

        try{
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, filename, new ByteArrayInputStream(content.getBytes()));
            // 设置该属性可以返回response。如果不设置，则返回的response为空。
            putObjectRequest.setProcess("true");
            // 上传字符串。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            return 200 == result.getResponse().getStatusCode();
        } catch (OSSException oe) {
            logger.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            logger.error("Error Message:" + oe.getErrorMessage());
            logger.error("Error Code:" + oe.getErrorCode());
            logger.error("Request ID:" + oe.getRequestId());
            logger.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            logger.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            logger.error("Error Message:" + ce.getMessage());
        }
        return false;
    }

    public boolean deleteFile(String bucketName, String filename) {
        try {
            // 删除文件或目录。如果要删除目录，目录必须为空。
            ossClient.deleteObject(bucketName, filename);
            return true;
        } catch (OSSException oe) {
            logger.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            logger.error("Error Message:" + oe.getErrorMessage());
            logger.error("Error Code:" + oe.getErrorCode());
            logger.error("Request ID:" + oe.getRequestId());
            logger.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            logger.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            logger.error("Error Message:" + ce.getMessage());
        }
        return false;
    }

    public boolean copyFile(String sourceBucketName, String sourceFileName, String targetBucketName, String targetFileName) {
        try {
            CopyObjectResult result = ossClient.copyObject(sourceBucketName, sourceFileName, targetBucketName, targetFileName);
            return 200 == result.getResponse().getStatusCode();
        } catch (OSSException oe) {
            logger.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            logger.error("Error Message:" + oe.getErrorMessage());
            logger.error("Error Code:" + oe.getErrorCode());
            logger.error("Request ID:" + oe.getRequestId());
            logger.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            logger.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            logger.error("Error Message:" + ce.getMessage());
        }
        return false;
    }

    public boolean cutFile(String sourceBucketName, String sourceFileName, String targetBucketName, String targetFileName) {
        try {
            CopyObjectResult result = ossClient.copyObject(sourceBucketName, sourceFileName, targetBucketName, targetFileName);
            // 删除文件或目录。如果要删除目录，目录必须为空。
            ossClient.deleteObject(sourceBucketName, sourceFileName);
            return 200 == result.getResponse().getStatusCode();
        } catch (OSSException oe) {
            logger.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            logger.error("Error Message:" + oe.getErrorMessage());
            logger.error("Error Code:" + oe.getErrorCode());
            logger.error("Request ID:" + oe.getRequestId());
            logger.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            logger.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            logger.error("Error Message:" + ce.getMessage());
        }
        return false;
    }

    public boolean renameFile(String sourceBucketName, String sourceFileName, String targetBucketName, String targetFileName) {
        return this.cutFile(sourceBucketName, sourceFileName, targetBucketName, targetFileName);
    }

    public byte[] getContent(String sourceBucketName, String fileName) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try(OSSObject object = ossClient.getObject(sourceBucketName, fileName)){
            byte[] b = new byte[1024];
            int c;
            while ((c = object.getObjectContent().read(b)) != -1) {
                os.write(b, 0, c);
            }
        }catch (OSSException oe) {
            logger.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            logger.error("Error Message:" + oe.getErrorMessage());
            logger.error("Error Code:" + oe.getErrorCode());
            logger.error("Request ID:" + oe.getRequestId());
            logger.error("Host ID:" + oe.getHostId());
        } catch (Throwable ce) {
            logger.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            logger.error("Error Message:" + ce.getMessage());
        }
        return os.toByteArray();
    }

    public boolean appendContent(String bucketName,String fileName, String content) {
        try {
            ObjectMetadata headObject = ossClient.headObject(bucketName, fileName);
            if ("Appendable".equals(headObject.getObjectType())) {
                AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucketName, fileName, new ByteArrayInputStream(content.getBytes()));
                appendObjectRequest.setPosition(0L);
                AppendObjectResult result = ossClient.appendObject(appendObjectRequest);
                return 200==result.getResponse().getStatusCode();
            }
        }catch (OSSException oe) {
            logger.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            logger.error("Error Message:" + oe.getErrorMessage());
            logger.error("Error Code:" + oe.getErrorCode());
            logger.error("Request ID:" + oe.getRequestId());
            logger.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            logger.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            logger.error("Error Message:" + ce.getMessage());
        }
        return false;
    }

    @Override
    public boolean saveFile(String filename, String content) {
        return this.saveFile( bucketName, filename, content);
    }

    @Override
    public boolean deleteFile(String filename) {
        return this.deleteFile(bucketName,filename);
    }

    @Override
    public boolean copyFile(String sourceFileName, String targetFileName) {
        return this.copyFile(bucketName,sourceFileName,bucketName,targetFileName);
    }

    @Override
    public boolean cutFile(String sourceFileName, String targetFileName) {
        return this.cutFile(bucketName,sourceFileName,bucketName,targetFileName);
    }

    @Override
    public boolean renameFile(String oldFileName, String newFileName) {
        return this.renameFile(bucketName,oldFileName,bucketName,newFileName);
    }

    @Override
    public byte[] getContent(String fileName) {
        return this.getContent(bucketName,fileName);
    }

}
